package cn.dankal.lequ.domain.download;

import android.os.Bundle;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import cn.dankal.lequ.commom.appcomponent.MyApplication;


public class DownloadManager {

    public static final int STATE_UNDOWNLOAD = 0;                                    // 未下载
    public static final int STATE_DOWNLOADING = 1;                                    // 下载中
    public static final int STATE_PAUSEDOWNLOAD = 2;                                    // 暂停下载
    public static final int STATE_WAITINGDOWNLOAD = 3;                                    // 等待下载
    public static final int STATE_DOWNLOADFAILED = 4;                                    // 下载失败
    public static final int STATE_DOWNLOADED = 5;                                    // 下载完成
    public static final int STATE_INSTALLED = 6;                                    // 已安装

    private static DownloadManager instance;
    // 记录正在下载的一些downLoadInfo
    public Map<String, DownLoadInfo> mDownLoadInfoMaps = new HashMap<String, DownLoadInfo>();

    private DownloadManager() {

    }

    public static DownloadManager getInstance() {
        if (instance == null) {
            synchronized (DownloadManager.class) {
                if (instance == null) {
                    instance = new DownloadManager();
                }
            }
        }
        return instance;
    }

    /**
     * 用户点击了下载按钮
     */
    public void downLoad(DownLoadInfo info) {
        mDownLoadInfoMaps.put(info.packageName, info);

		/*############### 当前状态: 未下载 ###############*/
        info.state = STATE_UNDOWNLOAD;
        notifyObservers(info);
        /*#######################################*/

		/*############### 当前状态: 等待状态 ###############*/
        info.state = STATE_WAITINGDOWNLOAD;
        notifyObservers(info);
        /*#######################################*/
        // 得到线程池,执行任务
        DownLoadTask task = new DownLoadTask(info);
        info.task = task;// downInfo身上的task赋值
        ThreadPoolFactory.getDownLoadPool().execute(task);
    }

    public class DownLoadTask implements Runnable {
        DownLoadInfo mInfo;

        public DownLoadTask(DownLoadInfo info) {
            super();
            mInfo = info;
        }

        @Override
        public void run() {
            // 正在发起网络请求下载apk
            // http://localhost:8080/GooglePlayServer/download?
            // name=app/com.itheima.www/com.itheima.www.apk&range=0
                /*############### 当前状态: 下载中 ###############*/
            mInfo.state = STATE_DOWNLOADING;
            notifyObservers(mInfo);
                /*#######################################*/


//            mInfo.curProgress = mInfo.loadedLength;// ③处理初始进度
            // 下载地址
            //// TODO:  0012  下载地址
//				String url = URLS.DOWNLOADBASEURL;

            HttpURLConnection connection = null;
            URL url = null;
            FileOutputStream out = null;
            InputStream in = null;
            String inPath = mInfo.savePath + "/" + mInfo.packageName + ".apk";

            try {
                url = new URL(mInfo.url);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(3000);
                if (mInfo.curProgress > 0 && mInfo.curProgress < mInfo.maxLength) {
                    connection.setRequestProperty("Range", "bytes=" + mInfo.curProgress + "-");
                    Log.i("down123", "begin to Range");
                }
                connection.connect();
                Bundle bundle = new Bundle();

                Log.i("down123", "connection.getResponseCode()   " + connection.getResponseCode());

                if (connection.getResponseCode() == 200 ||
                        connection.getResponseCode() == 206) {

                    boolean isPause = false;
                    Log.i("down123", "begin to download");
                    out = new FileOutputStream(inPath, true);
                    in = connection.getInputStream();
                    if (mInfo.curProgress == 0) {
                        mInfo.maxLength = connection.getContentLength();
                        mInfo.maxProgress = new BigDecimal(mInfo.maxLength).divide(new BigDecimal(1024 * 1024), 2, BigDecimal.ROUND_HALF_UP).doubleValue();
                    }

                    byte[] b = new byte[1024];
                    int read = 0;

                    while ((read = in.read(b)) != -1) {
                        if (mInfo.state == STATE_PAUSEDOWNLOAD) {
//                            mInfo.loadedLength = mInfo.curProgress;
                            isPause = true;
                            break;
                        }

                        mInfo.curProgress += read;
                        out.write(b, 0, read);
                        if (mInfo.curProgress / 1024 % 15 == 0) {
                                /*############### 当前状态: 下载中 ###############*/
                            mInfo.state = STATE_DOWNLOADING;
                            notifyObservers(mInfo);
                        }
                    }


                    if (isPause) {// 用户暂停了下载走到这里来了
                            /*############### 当前状态: 暂停 ###############*/
                        mInfo.state = STATE_PAUSEDOWNLOAD;
                        notifyObservers(mInfo);
                            /*#######################################*/
                    } else {// 下载完成走到这里来
                            /*############### 当前状态: 下载完成 ###############*/
                        mInfo.state = STATE_DOWNLOADED;
                        notifyObservers(mInfo);




                            /*#######################################*/
                    }
                } else {
                    /*############### 当前状态: 下载失败 ###############*/
                    mInfo.state = STATE_DOWNLOADFAILED;
                    notifyObservers(mInfo);
                    /*#######################################*/
                }
            } catch (Exception e) {
                e.printStackTrace();
                /*############### 当前状态: 下载失败 ###############*/
                mInfo.state = STATE_DOWNLOADFAILED;
                notifyObservers(mInfo);
                /*#######################################*/
            } finally {
                try {
                    if (in != null)
                        in.close();
                    if (out != null)
                        out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

        /**
         * @des 暴露当前状态, 也就是需要提供downLoadInfo
         * @call 外界需要知道最新的state的时候
         */
        public DownLoadInfo getDownLoadInfo(AppInfoBean data) {
            // 已安装
            if (CommonUtils.isInstalled(MyApplication.getAppContext(), data.packageName)) {
                DownLoadInfo info = generateDownLoadInfo(data);
                info.state = STATE_INSTALLED;// 已安装
                return info;
            }
            // 下载完成
            DownLoadInfo info = generateDownLoadInfo(data);
            File saveApk = new File(info.savePath);
            if (saveApk.exists()) {// 如果存在我们的下载目录里面
                if (saveApk.length() == data.size) {
                    info.state = STATE_DOWNLOADED;// 下载完成
                    return info;
                }
            }

            /**
             下载中
             暂停下载
             等待下载
             下载失败
             */
            DownLoadInfo downLoadInfo = mDownLoadInfoMaps.get(data.packageName);
            if (downLoadInfo != null) {
                return downLoadInfo;
            }

            // 未下载
            DownLoadInfo tempInfo = generateDownLoadInfo(data);
            tempInfo.state = STATE_UNDOWNLOAD;// 未下载
            return tempInfo;
        }

        /**
         * 根据AppInfoBean生成一个DownLoadInfo,进行一些常规的赋值,也就是对一些常规属性赋值(除了state之外的属性)
         */
        public DownLoadInfo generateDownLoadInfo(AppInfoBean data) {
            String dir = FileUtils.getDownloadPath();// sdcard/android/data/包名/download
            File file = new File(dir, data.packageName + ".apk");// sdcard/android/data/包名/download/com.itheima.www.apk
            // 保存路径
            String savePath = file.getAbsolutePath();// sdcard/android/data/包名/download/com.itheima.www.apk

            // 初始化一个downLoadInfo
            DownLoadInfo info = new DownLoadInfo();
            // 相关赋值
            info.savePath = savePath;
            info.url = data.downloadUrl;
            info.packageName = data.packageName;
            info.maxProgress = data.size;
            info.curProgress = 0;
            return info;
        }

        /**
         * 暂停下载
         */
        public void pause(DownLoadInfo info) {
        /*############### 当前状态: 暂停 ###############*/
            info.state = STATE_PAUSEDOWNLOAD;
            notifyObservers(info);
        /*#######################################*/
        }

        /**
         * 取消下载
         */
        public void cancel(DownLoadInfo info) {
            Runnable task = info.task;
            // 找到线程池,移除任务
            ThreadPoolFactory.getDownLoadPool().removeTask(task);

		/*############### 当前状态: 未下载 ###############*/
            info.state = STATE_UNDOWNLOAD;
            notifyObservers(info);
        /*#######################################*/
        }
    }


    List<DownLoadObserver> downLoadObservers = new LinkedList<>();

    /**
     * 添加观察者
     */
    public void addObserver(DownLoadObserver observer) {
        if (observer == null) {
            throw new NullPointerException("observer == null");
        }
        synchronized (this) {
            if (!downLoadObservers.contains(observer))
                downLoadObservers.add(observer);
        }
    }

    /**
     * 删除观察者
     */
    public synchronized void deleteObserver(DownLoadObserver observer) {
        downLoadObservers.remove(observer);
    }

    /**
     * 通知观察者数据改变
     */
    public void notifyObservers(DownLoadInfo info) {
        for (DownLoadObserver observer : downLoadObservers) {
            observer.onDownLoadInfoChange(info);
        }
    }

	/*=============== 自定义观察者设计模式  end ===============*/


    /*=============== 自定义观察者设计模式  begin ===============*/
    public interface DownLoadObserver {
        void onDownLoadInfoChange(DownLoadInfo info);
    }

}
